;;; ----------------------------------------------------------------------
;;; &Modem protocol client
;;; Copyright 2017 Chris Baird,, <cjb@@brushtail.apana.org.au>
;;; Distributed to the GPLV3 terms and conditions.
;;; --
;;; build with cc65's ca65 thusly:
;;;    $ ca65 -l andmodem.asm && ld65 -t none andmodem.o
;;; --
;;; The 2400 baud routines I saved from Usenet 26 years ago!
;;; ---
;;; [$Id]
;;; ----------------------------------------------------------------------

	    OPEN	= $FFC0
	    CHKIN	= $FFC6
	    CHKOUT	= $FFC9
	    CHROUT	= $FFD2
	    SETNAM	= $FFBD
	    SETLFS 	= $FFBA
	    CLALL	= $FFE7
	    CLRCHN	= $FFCC

	    buffer 	= 1024+40
            BUFFERMAX   = 254

            reqblock    = 251
	    pointer	= 252
            blocklen    = 254
	    checksum    = 255

;;; ----------------------------------------------------------------------

	   .org 52555

downloader:
	    ldy #0
            sty reqblock
dl1:
            lda banner,y
	    jsr CHROUT
	    iny
	    cmp #0
	    bne dl1

	    ;; open RS232 channel

	    lda #2
	    ldx #<controlstring
	    ldy #>controlstring
	    jsr SETNAM
	    lda #2
            tax
	    ldy #3
	    jsr SETLFS
	    jsr OPEN
	    ldx #2
	    jsr CHKIN
	    ldx #2
	    jsr CHKOUT

            jsr rssetup
            jsr rsenable

;;; ----------------------------------------------------------------------

mainloop:
            lda reqblock
	    jsr rsout ;CHROUT

mloop0:
	    jsr rsget           ; a marker helps with error recovery..
            cmp #'&'
            bne mloop0          ; todo - timeouts

            ;; get destination address

	    jsr rsget
            sta pointer
            jsr rsget
            sta pointer+1

            ;; check if EOF

	    cmp #255
	    bne mbr1
	    cmp pointer
	    bne mbr1

            jsr rsdisable       ; exit program
            ;jsr CLALL
	    ;jsr CLRCHN
            brk

            ;; get block length
mbr1:
            jsr rsget
            sta blocklen

            ;; checksum setup

            ;clc
            lda pointer
            adc pointer+1
            clc
            adc blocklen
            sta checksum

            ;; get block

            ldy #0
mloop1:
            jsr rsget
            sta buffer,y
            ;clc
            adc checksum
            sta checksum
            iny

            cpy #BUFFERMAX            ; overflow? -- reset everything
            bne mbr2
            beq mainloop

mbr2:
            cpy blocklen
            bne mloop1

            ;; get checksum

            jsr rsget
            cmp checksum
            bne mainloop

            ;; received block is okay, copy it to memory

mloop2:
            dey
            cpy #255
            beq mloop3
            lda buffer,y
            sta (pointer),y
            jmp mloop2

mloop3:
            ;; prepare for the next block

            inc reqblock

            ;; save location of last byte for BASIC's needs

	    clc
	    lda pointer
	    adc blocklen
	    sta 45
	    lda pointer+1
	    adc #0
	    sta 46

            ;; increase screen counter

	    ldy #2
incdec:
            clc
	    lda linetxt,y
	    adc #1
	    sta linetxt,y
	    cmp #'9'+1
	    bcc continue
	    lda #'0'
	    sta linetxt,y
	    dey
	    bpl incdec

continue:
	    jmp mainloop


;;; ----------------------------------------------------------------------

            ;; control register byte
	    BAUD300 	= 6
	    BAUD1200 	= 8
	    BAUD2400 	= 10
	    WORD8       = 0
	    WORD7       = 32
	    ONESTOPBIT 	= 0

            ;; command register byte
	    THREEWIRE 	= 0
	    FLOWCONTROL = 1
	    FULLDUPLEX 	= 0
	    HALFDUPLEX 	= 16
	    NOPARITY 	= 0
	    ODDPARITY 	= 32
	    EVENPARITY 	= 96

controlstring:
	    .byte BAUD2400+WORD8+ONESTOPBIT, THREEWIRE+FULLDUPLEX+NOPARITY

banner:
	    .byte 144, 147, 5, "000", 13, 0

	    linetxt = 1024      ; where the "000" appears in memory

;;; ----------------------------------------------------------------------

;;; Replacement  rs-232 routine for the Commodore 64
;;; to enable reliable transmission at 2400 bits/sec

;;; This was posted to comp.sys.cbm in 1989 (when I saved a copy!),
;;; after being distributing about Fidonet earlier. Authorship
;;; unknown.

            ribuf  = $f7        ; rs232 input buffer pointer
            robuf  = $f9        ; rs232 ouput buffer pointer
            baudof = $0299      ; rs232 baud rate
            ridbe  = $029b      ; rs232 index to end of input buffer
            ridbs  = $029c      ; rs232 start of input buffer
            rodbs  = $029d      ; rs232 start of output buffer
            rodbe  = $029e      ; rs232 index to end of ouput buffer
            enabl  = $02a1      ; rs232 enable
            nminv  = $0318      ; vector: nmi
            ichkin = $031e      ; vector: chkin
            ibsout = $0326      ; vector: chrout
            dataa  = $dd00      ; data port a
            datab  = $dd01      ; data port b
            timblo = $dd06      ; timer B lo byte
            timbhi = $dd07      ; timer B hi byte
            rdnmi  = $dd0d      ; read/mask nmi
            crega  = $dd0e      ; cia control reg a
            cregb  = $dd0f      ; cia control reg b
            rstkey = $fe56
            norest = $fe72
            return = $febc
            oldout = $f1ca
            oldchk = $f21b
            findfn = $f30f
            devnum = $f31f
            nofile = $f701

            ;;jmp rssetup       ; setup new rs-232 routine
            ;;jmp rsenable      ; enable the new routine
            ;;jmp rsdisable     ; disable the new routine
            ;;jmp rsget
            ;;jmp rsout

strt24:     .byte 203,1
strt12:     .byte  66,4
strt03:     .byte  51,19
full24:     .byte 165,1
full12:     .byte  77,3
full03:     .byte  82,13

;;;

rssetup:
            lda #<rsnmi         ; redirect nmi vector
            ldy #>rsnmi
            sta nminv+00
            sty nminv+01

            lda #<nchkin        ; redirect chkin vector
            ldy #>nchkin
            sta ichkin+00
            sty ichkin+01

            lda #<nbsout        ; redirect chrout vector
            ldy #>nbsout
            sta ibsout+00
            sty ibsout+01
            rts

;;; -----  new nmi routine here  -----------------------

rsnmi:
            pha                 ; save registers
            txa
            pha
            tya
            pha
            cld
            ldx timbhi
            lda #$7f
            sta rdnmi
            lda rdnmi
            bpl notcia
            cpx timbhi
            ldy datab
            bcs mask
            ora #$02
            ora rdnmi

mask:
            and enabl
            tax
            lsr
            bcc ckflag
            lda dataa
            and #$fb
            ora $b5
            sta dataa
ckflag:
            txa
            and #$10
            beq nmion

strtlo:
            lda #$42
            sta timblo

strthi:
            lda #$04
            sta timbhi

            lda #$11
            sta cregb
            lda #$12
            eor enabl
            sta enabl
            sta $dd0d

fulllo:
            lda #$4d
            sta timblo

fullhi:
            lda #$03
            sta timbhi

            lda #$08
            sta $a8
            bne chktxd

notcia:
            ldy #00
            jmp rstkey

nmion:
            lda enabl
            sta rdnmi
            txa
            and #$02
            beq chktxd
            tya
            lsr
            ror $aa
            dec $a8
            bne txd
            ldy ridbe
            lda $aa
            sta (ribuf),y
            inc ridbe
            lda #$00
            sta cregb
            lda #$12

switch:
            ldy #$7f
            sty rdnmi
            eor enabl
            sta enabl
            sta rdnmi

txd:
            txa
            lsr

chktxd:
            bcc exit
            dec $b4
            bmi char
            lda #$04
            ror $b6
            bcs store

low:
            lda #$00

store:
            sta $b5

exit:
            jmp return

char:
            ldy rodbs
            cpy rodbe
            beq txoff

getbuf:
            lda (robuf),y
            inc rodbs
            sta $b6
            lda #$09
            sta $b4
            bne low

txoff:
            ldx #$00
            stx crega
            lda #$01
            bne switch

;;; -----  routine to disable the new-rs232  ------------

rsdisable:
            pha
rsd1:
            lda enabl
            and #$03
            bne rsd1
            lda #$10
            sta $dd0d
            lda #$02
            and enabl
            bne rsd1
            sta enabl
            pla
            rts

;;; -----------------------------------------------------

nbsout:
            pha
            lda $9a
            cmp #$02
            bne notmod
            pla
rsout:
            sta $9e
            sty $97
point:
            ldy rodbe
            sta (robuf),y
            iny
            cpy rodbs
            beq fulbuf
            sty rodbe

strtup:
            lda enabl
            and #$01
            bne ret3
            sta $b5
            lda #$09
            sta $b4
            ldy rodbs
            lda (robuf),y
            sta $b6
            inc rodbs
            lda baudof
            sta $dd04
            lda baudof+1
            sta $dd05
            lda #$11
            sta crega
            lda #$81

change:
            sta rdnmi
            php
            sei
            ldy #$7f
            sty rdnmi
            ora enabl
            sta enabl
            sta rdnmi
            plp

ret3:
            clc
            ldy $97
            lda $9e
            rts

fulbuf:
            jsr strtup
            jmp point

notmod:
            pla
            jmp oldout

;;;

nchkin:
            jsr findfn
            bne nosuch
            jsr devnum
            lda $ba
            cmp #$02
            bne back
            sta $99

rsenable:
            sta $9e
            sty $97

baud:
            lda baudof+1
            and #$06
            tay
            lda strt24,y
            sta strtlo+1
            lda strt24+1,y
            sta strthi+1
            lda full24,y
            sta fulllo+1
            lda full24+1,y
            sta fullhi+1
            lda enabl
            and #$12
            bne ret1
            sta cregb
            lda #$90
            jmp change

nosuch:
            jmp nofile

back:
            lda $ba
            jmp oldchk


;;; -----  new rs232 get routine  -----------------------

rsget:
            sta $9e
            sty $97
            ldy ridbs
rget3:      cpy ridbe
            beq rget3           ;cjb -- blocking
            lda (ribuf),y
            sta $9e
            inc ridbs
ret1:
            clc
            ldy $97
            lda $9e
            rts

;;; ----------------------------------------------------------------------
;;; ----------------------------------------------------------------------
